#include "udpsocketimpl.h"

CUdpSocketImpl::CUdpSocketImpl()
{
	m_ulConTmSec			=	5;
	m_sock					=	INVALID_SOCKET;
}
CUdpSocketImpl::~CUdpSocketImpl()
{
	logi("CUdpSocketImpl::~CUdpSocketImpl");
}
std_method_impl CUdpSocketImpl::CUdpSocketImpl::CloseIo(UINT rw)
{
	rc_assert(udp_close() == S_SUCCESS, S_ERROR)
	return S_OK;
}
std_method_impl CUdpSocketImpl::CUdpSocketImpl::BindIo()
{
	rc_assert(m_sock != INVALID_SOCKET, S_ERROR);
	rc_assert(udp_assign(&m_sock) == S_SUCCESS, S_ERROR)
	return S_OK;
}
std_method_impl CUdpSocketImpl::CUdpSocketImpl::OpenIo()
{
	//rc_assert(udp_init() == S_SUCCESS, E_FAIL)
	return S_OK;
}
std_method_impl CUdpSocketImpl::CreateSock()
{
	m_sock = INVALID_SOCKET;
	m_sock = _createsock(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
	rc_assert(m_sock != INVALID_SOCKET, E_FAIL)
	return S_OK;
}
std_method_impl CUdpSocketImpl::CloseSock()
{
	rc_assert(m_sock != INVALID_SOCKET, E_FAIL)
	_closesock(m_sock);
	m_sock = INVALID_SOCKET;
	return S_OK;
}
std_method_impl CUdpSocketImpl::IsOpen()
{
	return udp_is_open() == S_SUCCESS ? S_OK : E_FAIL;
}
std_method_impl CUdpSocketImpl::AttachSock(_sock_t sock)
{
	rc_assert(sock != INVALID_SOCKET, E_FAIL)
	m_sock = sock;
	return S_OK;
}

std_method_type_impl(_sock_t) CUdpSocketImpl::DetachSock()
{
	return m_sock;
}
std_method_impl CUdpSocketImpl::SetOption(LPCSTR opt, int val)
{
	HRESULT		hr = S_OK;

	if (s_strcmp(opt, SOL_REUSEDDR) == 0) {

		SetReuseAddr(&m_sock, val);
	}
	else if (s_strcmp(opt, SOL_NODELAY) == 0) {

		SetNoDelay(&m_sock, val);
	}
	else if (s_strcmp(opt, SOL_LINGER) == 0) {

		SetLinger(&m_sock, val);
	}
	else if (s_strcmp(opt, SOL_KEEPLIVE) == 0) {

		SetKeepalive(&m_sock, val);
	}
	else if (s_strcmp(opt, SOL_CORK) == 0) {

		SetCork(&m_sock, val);
	}
	else if (s_strcmp(opt, SOL_NOSIGPIPE) == 0) {

		SetNoSigPipe(&m_sock, val);
	}
	else if (s_strcmp(opt, SOL_RECVLEN) == 0) {

		SetRecvBufLen(&m_sock, val);
	}
	else if (s_strcmp(opt, SOL_SENDLEN) == 0) {

		SetSendBufLen(&m_sock, val);
	}
	else if (s_strcmp(opt, SOL_SENDTM) == 0) {

		SetSendTimeOut(&m_sock, val);
	}
	else if (s_strcmp(opt, SOL_RECVTM) == 0) {

		SetRecvTimeOut(&m_sock, val);
	}
	else if (s_strcmp(opt, SOL_CONTM) == 0) {

		SetConTimeOut(&m_sock, val);
	}
	else if (s_strcmp(opt, SOL_SENDLOWAT) == 0) {

		SetSendLoWat(&m_sock, val);
	}
	else if (s_strcmp(opt, SOL_RECVLOWAT) == 0) {

		SetRecvLoWat(&m_sock, val);
	}
	else {
		return E_FAIL;
	}

	m_MapSockOption[opt] = val;

	return hr;
}
std_method_impl CUdpSocketImpl::GetOption(LPCSTR opt, int* val)
{
	HRESULT		hr = S_OK;
	SocketOption option = m_MapSockOption.find(opt);
	rc_assert(option != m_MapSockOption.end(), E_FAIL);
	*val = option->second;
	return hr;
}
std_method_type_impl(BUFFER_SIZE) CUdpSocketImpl::SyncSend(NET_ADDR addr, NET_PORT port,
	BUFFER_PTR buf, BUFFER_SIZE size)
{
	rc_assert(addr != NULL, E_FAIL)
	rc_assert(port != INVALID_NET_PORT, E_FAIL)
	return this->sync_write(addr, port, buf, size);
}
std_method_type_impl(BUFFER_SIZE) CUdpSocketImpl::SyncRecv(NET_ADDR addr, NET_PORT port,
	BUFFER_PTR buf, BUFFER_SIZE size)
{
	rc_assert(addr != NULL, E_FAIL)
	rc_assert(port != INVALID_NET_PORT, E_FAIL)
	return this->sync_read(addr, port, buf, size);
}
std_method_impl CUdpSocketImpl::ReadIo(NET_ADDR addr, NET_PORT port,
	IBase* pBase, event_id event)
{
	HRESULT		hr = S_OK;
	rc_assert(pBase != NULL, E_FAIL)

	OperationPtr pOperation;
	hr = pBase->QueryInterface(IID_IOperation, (void**)&pOperation);
	rc_assert(hr == S_OK, E_FAIL)

	this->ctx.data = pBase;
	this->ctx.event = event;

	hr = pOperation->GetPtr(&this->ctx.rptr);
	rc_assert(this->ctx.rptr != NULL, E_FAIL)
	rc_assert(hr == S_OK, E_FAIL)

	hr = pOperation->GetExpect(&this->ctx.rlen);
	rc_assert(hr == S_OK, E_FAIL)

	int error = async_read(addr, port, this->ctx.rptr, this->ctx.rlen);
	return (S_SUCCESS == error) ? S_OK : E_FAIL;
}
std_method_impl CUdpSocketImpl::WriteIo(NET_ADDR addr, NET_PORT port,
	IBase* pBase, event_id event)
{
	HRESULT		hr = S_OK;
	rc_assert(pBase != NULL, E_FAIL)

	OperationPtr pOperation;
	hr = pBase->QueryInterface(IID_IOperation, (void**)&pOperation);
	rc_assert(hr == S_OK, E_FAIL)

	this->ctx.data = pBase;
	this->ctx.event = event;

	hr = pOperation->GetPtr(&this->ctx.wptr); 
	rc_assert(this->ctx.wptr != NULL, E_FAIL)
	rc_assert(hr == S_OK, E_FAIL)

	hr = pOperation->GetExpect(&this->ctx.wlen);
	rc_assert(hr == S_OK, E_FAIL)

	int error = async_write(addr, port, this->ctx.wptr, this->ctx.wlen);
	return (S_SUCCESS == error) ? S_OK : E_FAIL;
}
void CUdpSocketImpl::DgramWritecb(void *data, BUFFER_SIZE len)
{
	IOperation* pOperation = static_cast<IOperation*>(this->ctx.data);
	c_assert(pOperation != NULL);
	pOperation->SetResult(0, len);
	pOperation->Post(this->ctx.event, 0);
}
void CUdpSocketImpl::DgramReadcb(void *data, BUFFER_SIZE len)
{
	IOperation* pOperation = static_cast<IOperation*>(this->ctx.data);
	c_assert(pOperation != NULL);
	pOperation->SetResult(0, len);
	pOperation->Post(this->ctx.event, 0);
}
void CUdpSocketImpl::DgramEventcb(void *data, event_id what)
{
	IOperation* pOperation = static_cast<IOperation*>(this->ctx.data);
	c_assert(pOperation != NULL);

	ULONG error_code = S_SUCCESS;
	if (what == DGRAM_READ_ERROR) {
		pOperation->SetResult(OP_READERROR, 0);
		error_code = OP_READERROR;
	}

	if (what == DGRAM_WRITE_ERROR) {
		pOperation->SetResult(OP_WRITEERROR, 0);
		error_code = OP_WRITEERROR;
	}

	if (what == DGRAM_WRITE_TIMEOUT) {
		pOperation->SetResult(OP_WRITETIMEOUT, 0);
		error_code = OP_WRITETIMEOUT;
	}

	if (what == DGRAM_READ_TIMEOUT) {
		pOperation->SetResult(OP_READTIMEOUT, 0);
		error_code = OP_READTIMEOUT;
	}

	pOperation->SetResult(error_code, 0);
	pOperation->Post(this->ctx.event, error_code);
}
IoDgramBase* CUdpSocketImpl::GetIoUdp()
{
	return this;
}
